// Fluxions 3D Engine
// fluxions/glut_extensions.hpp
// Copyright (C) 2000-2011 Jonathan Metzgar
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

#include <algorithm>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "fluxions/glut_extensions.hpp"


namespace GlutTemplatePrivate
{
	extern int g_screenWidth;
}


using namespace std;


void glutWireBox(float x1, float y1, float z1, float x2, float y2, float z2)
{
	float minX = min(x1, x2);
	float maxX = max(x1, x2);
	float minY = min(y1, y2);
	float maxY = max(y1, y2);
	float minZ = min(z1, z2);
	float maxZ = max(z1, z2);
	
	glBegin(GL_LINE_LOOP);
	glNormal3f(0, -1, 0);
	glTexCoord2f(1, 0); glVertex3f(minX, minY, minZ);
	glTexCoord2f(0, 0); glVertex3f(maxX, minY, minZ);
	glTexCoord2f(0, 1); glVertex3f(maxX, minY, maxZ);
	glTexCoord2f(1, 1); glVertex3f(minX, minY, maxZ);
	glEnd();
	
	
	glBegin(GL_LINE_LOOP);
	glNormal3f(0, 1, 0);
	glTexCoord2f(0, 0); glVertex3f(minX, maxY, minZ);
	glTexCoord2f(1, 0); glVertex3f(maxX, maxY, minZ);
	glTexCoord2f(1, 1); glVertex3f(maxX, maxY, maxZ);
	glTexCoord2f(0, 1); glVertex3f(minX, maxY, maxZ);
	glEnd();
	
	
	glBegin(GL_LINE_LOOP);
	glNormal3f(-1, 0, 0);
	glTexCoord2f(0, 1); glVertex3f(minX, minY, minZ);
	glTexCoord2f(0, 0); glVertex3f(minX, maxY, minZ);
	glTexCoord2f(1, 0); glVertex3f(minX, maxY, maxZ);
	glTexCoord2f(1, 1); glVertex3f(minX, minY, maxZ);
	glEnd();
	
	
	glBegin(GL_LINE_LOOP);
	glNormal3f(1, 0, 0);
	glTexCoord2f(1, 1); glVertex3f(maxX, minY, minZ);
	glTexCoord2f(1, 0); glVertex3f(maxX, maxY, minZ);
	glTexCoord2f(0, 0); glVertex3f(maxX, maxY, maxZ);
	glTexCoord2f(0, 1); glVertex3f(maxX, minY, maxZ);
	glEnd();
	
	
	glBegin(GL_LINE_LOOP);
	glNormal3f(0, 0, -1);
	glTexCoord2f(1, 1); glVertex3f(minX, minY, minZ);
	glTexCoord2f(0, 1); glVertex3f(maxX, minY, minZ);
	glTexCoord2f(0, 0); glVertex3f(maxX, maxY, minZ);
	glTexCoord2f(1, 0); glVertex3f(minX, maxY, minZ);
	glEnd();
	
	
	glBegin(GL_LINE_LOOP);
	glNormal3f(0, 0, 1);
	glTexCoord2f(0, 1); glVertex3f(minX, minY, maxZ);
	glTexCoord2f(1, 1); glVertex3f(maxX, minY, maxZ);
	glTexCoord2f(1, 0); glVertex3f(maxX, maxY, maxZ);
	glTexCoord2f(0, 0); glVertex3f(minX, maxY, maxZ);	
	glEnd();
}


void glutSolidBox(float x1, float y1, float z1, float x2, float y2, float z2)
{
	float minX = min(x1, x2);
	float maxX = max(x1, x2);
	float minY = min(y1, y2);
	float maxY = max(y1, y2);
	float minZ = min(z1, z2);
	float maxZ = max(z1, z2);
	
	glBegin(GL_QUADS);
	
	glNormal3f(0, -1, 0);
	glTexCoord2f(1, 0); glVertex3f(minX, minY, minZ);
	glTexCoord2f(0, 0); glVertex3f(maxX, minY, minZ);
	glTexCoord2f(0, 1); glVertex3f(maxX, minY, maxZ);
	glTexCoord2f(1, 1); glVertex3f(minX, minY, maxZ);
	
	
	glNormal3f(0, 1, 0);
	glTexCoord2f(0, 0); glVertex3f(minX, maxY, minZ);
	glTexCoord2f(1, 0); glVertex3f(maxX, maxY, minZ);
	glTexCoord2f(1, 1); glVertex3f(maxX, maxY, maxZ);
	glTexCoord2f(0, 1); glVertex3f(minX, maxY, maxZ);
	
	
	glNormal3f(-1, 0, 0);
	glTexCoord2f(0, 1); glVertex3f(minX, minY, minZ);
	glTexCoord2f(0, 0); glVertex3f(minX, maxY, minZ);
	glTexCoord2f(1, 0); glVertex3f(minX, maxY, maxZ);
	glTexCoord2f(1, 1); glVertex3f(minX, minY, maxZ);
	
	
	glNormal3f(1, 0, 0);
	glTexCoord2f(1, 1); glVertex3f(maxX, minY, minZ);
	glTexCoord2f(1, 0); glVertex3f(maxX, maxY, minZ);
	glTexCoord2f(0, 0); glVertex3f(maxX, maxY, maxZ);
	glTexCoord2f(0, 1); glVertex3f(maxX, minY, maxZ);
	
	
	glNormal3f(0, 0, -1);
	glTexCoord2f(1, 1); glVertex3f(minX, minY, minZ);
	glTexCoord2f(0, 1); glVertex3f(maxX, minY, minZ);
	glTexCoord2f(0, 0); glVertex3f(maxX, maxY, minZ);
	glTexCoord2f(1, 0); glVertex3f(minX, maxY, minZ);
	
	
	glNormal3f(0, 0, 1);
	glTexCoord2f(0, 1); glVertex3f(minX, minY, maxZ);
	glTexCoord2f(1, 1); glVertex3f(maxX, minY, maxZ);
	glTexCoord2f(1, 0); glVertex3f(maxX, maxY, maxZ);
	glTexCoord2f(0, 0); glVertex3f(minX, maxY, maxZ);
	
	glEnd();
}


void glutCheckerboard(const float *whiteColor, const float *blackColor, const float xscale, float yscale, const float xtrans, const float ytrans)
{
	glBegin(GL_QUADS);
	for (int i = -4; i < 4; i++)
	{
		for (int j = -4; j < 4; j++)
		{
			glNormal3f(0, 0, 1);
			if ((j % 2 && i % 2) || j == i || (!(j % 2) && !(i % 2)))
				glColor4fv(whiteColor);
			else
				glColor4fv(blackColor);
				
			float x1, y1, x2, y2;
			x1 = (4 + i) / 8.0f;
			y1 = (4 + j) / 8.0f;
			x2 = (4 + (i+1)) / 8.0f;
			y2 = (4 + (j+1)) / 8.0f;
			//glRectf(x1, y1, x2, y2);
			float s1, t1, s2, t2;
			s1 = x1; t1 = y1; s2 = x2; t2 = y2;
			glTexCoord2f(s1, t1); glVertex2f(x1*xscale+xtrans, y1*yscale+ytrans);
			glTexCoord2f(s2, t1); glVertex2f(x2*xscale+xtrans, y1*yscale+ytrans);
			glTexCoord2f(s2, t2); glVertex2f(x2*xscale+xtrans, y2*yscale+ytrans);
			glTexCoord2f(s1, t2); glVertex2f(x1*xscale+xtrans, y2*yscale+ytrans);
		}
	}
	glEnd();
}


void glutLine2(float x1, float y1, float x2, float y2)
{
	glBegin(GL_LINES);
	glVertex2f(x1, y1);
	glVertex2f(x2, y2);
	glEnd();
}


void glutLine3(float x1, float y1, float z1, float x2, float y2, float z2)
{
	glBegin(GL_LINES);
	glVertex3f(x1, y1, z1);
	glVertex3f(x2, y2, z2);
	glEnd();
}


void glutBitmapString(void *font, const char *string)
{
	int len = strlen(string);
	int i = 0;
	
	for (i = 0; i < len; i++)
	{
		glutBitmapCharacter(font, string[i]);
	}	
}


void glutStrokeString(void *font, const char *string)
{
	int len = strlen(string);
	int i = 0;
	
	for (i = 0; i < len; i++)
	{
		glutStrokeCharacter(font, string[i]);
	}	
}


void glutBitmapPrintRight(void *font, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	int width = glutBitmapLength(font, (unsigned char *)buffer);
	glRasterPos2f(GlutTemplatePrivate::g_screenWidth - width, y);
	glutBitmapString(font, buffer);
}


void glutBitmapPrintLeft(void *font, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	glRasterPos2f(0, y);
	glutBitmapString(font, buffer);
}


void glutBitmapPrintCenter(void *font, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	int width = glutBitmapLength(font, (unsigned char *)buffer);
	glRasterPos2f((GlutTemplatePrivate::g_screenWidth - width) / 2.0, y);
	glutBitmapString(font, buffer);
}


void glutBitmapPrint(void *font, int x, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	glRasterPos2f(x, y);
	glutBitmapString(font, buffer);
}


void glutStrokePrintRight(void *font, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	int width = glutStrokeLength(font, (unsigned char *)buffer);
	glRasterPos2f(GlutTemplatePrivate::g_screenWidth - width, y);
	glutStrokeString(font, buffer);
}


void glutStrokePrintLeft(void *font, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	glRasterPos2f(0, y);
	glutStrokeString(font, buffer);
}


void glutStrokePrintCenter(void *font, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	int width = glutStrokeLength(font, (unsigned char *)buffer);
	glRasterPos2f((GlutTemplatePrivate::g_screenWidth - width) / 2.0, y);
	glutStrokeString(font, buffer);
}


void glutStrokePrint(void *font, int x, int y, const char *format, ...)
{
	char buffer[256];
	va_list va;
	va_start(va, format);
	vsnprintf(buffer, 256, format, va);
	glRasterPos2f(x, y);
	glutStrokeString(font, buffer);
}
